//////////////////////////////////////
// Fast Container Library           //
// MIT License - Copyright (c) 2012 //
//////////////////////////////////////

#pragma once

#include "common.h"


#define FC_INT32_WORDCOUNT(x) (((x - 1) / 32) + 1)
#define FC_INT64_WORDCOUNT(x) (((x - 1) / 64) + 1)
#define FC_INT32_BITCOUNT(x) (x > 0 ? (x * 32) : 32)
#define FC_INT64_BITCOUNT(x) (x > 0 ? (x * 64) : 64)

FC_NAMESPACE_BEGIN


inline size_t count_bits(size_t x)
	{
	#if defined(__GNUC__)
		return (size_t)__builtin_popcountl(x);
	#else
		//use the nifty bit counting trick.
		x = x - ((x >> 1) & 0x55555555);
		x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
		return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24;
	#endif
	}

inline size_t count_bits(uint64_t x)
	{
	#if defined(__GNUC__)
		return (uint64_t)__builtin_popcountll(x);
	#else
		size_t* p = (size_t*)&x;
		return count_bits( size_t(*p) ) + count_bits( size_t(*(p + 1)) );
	#endif
	}



// bit_reference
//
// class that holds a pointer to a specified integral block of memory along with a mask to a
// specific bit within that block. 
// bit_reference is used internally by bit-modifying classes such as bit_array and bitset
// and is placed here to remove template bloat and allow code reuse.

class bit_reference
{
public:
	bit_reference( size_t* ptr, size_t pos ) : _p(ptr), _mask(size_t(1) << pos) {}
	bit_reference& flip() { *_p ^= _mask; return *this; }

	operator bool() const { return (*_p & _mask) != 0; }
	bool operator~() const { return (*_p & _mask) == 0; }

	bit_reference& operator |=( bool value ) { if( value ) *_p |= _mask; return *this; }
	bit_reference& operator &=( bool value ) { if( !value ) *_p &= ~_mask; return *this; }
	bit_reference& operator ^=( bool value ) { if( value ) *_p ^= _mask; return *this; }

	bit_reference& operator =( const bit_reference& r ) { return operator =(r.operator bool()); }
	bit_reference& operator =( bool value )
	{
		if( value ) *_p |= _mask;
		else *_p &= ~_mask;
		return *this;
	}

protected:
	size_t* _p;
	size_t _mask;
};


FC_NAMESPACE_END

